package com.yvan.spring;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.yvan.SettingProperties;
import com.yvan.YvanUtil;
import com.yvan.platform.JsonWapper;
import com.yvan.platform.StringUtils;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.PropertiesPropertySource;
import org.springframework.web.context.support.StandardServletEnvironment;

import java.util.*;

/**
 * 获取本地与本地配置的Remote配置文件并合并
 * Created by EdifierWill on 2017/11/23.
 */
public class ConfigClient {

    private final static String CONFIG_DIR_PATH = "classpath:";
    private final static String APPLICATION_FILE_PREFIX = "application-";
    private final static String APPLICATION_FILE_SUFFIX = ".yml";
    private final static String APPLICATION_FILE_NAME = "application.yml";
    private List<String> extArgsList = null;

    public ConfigClient() {

    }

    public ConfigClient(String[] args) {
        if (args != null && args.length > 0) {
            extArgsList = Arrays.asList(args);
        }
    }

    public ConfigurableEnvironment getRemoteEnv(String sourceName) {

        ConfigurableEnvironment env = new StandardServletEnvironment();
        Properties properties = new Properties();
        Map<String, String> setting = readApplicationConfig();
        for (String key : setting.keySet()) {
            properties.setProperty(key, setting.get(key));
        }
        env.getPropertySources().addFirst(new PropertiesPropertySource(sourceName, properties));
        return env;
    }

    public JsonNode getBaseApplicationConfig() {

        return getBaseApplicationConfig(extArgsList);
    }

    public JsonNode getBaseApplicationConfig(List<String> argsList) {
        List<String> localConfigs = new ArrayList<>();
        String baseConfigPath = CONFIG_DIR_PATH + APPLICATION_FILE_NAME;
        JsonWapper base = YvanUtil.loadYamlResource(baseConfigPath);
        localConfigs.add(baseConfigPath);
        //TODO get active config file
        String activeApplicationConfig = "";
        if (argsList != null) {
            for (String arg : argsList) {
                if (arg.contains("--spring.profiles.active=")) {
                    activeApplicationConfig = arg.substring("--spring.profiles.active=".length());
                }
            }
        }
        if (StringUtils.isNullOrEmpty(activeApplicationConfig)) {
            if (base.contains("spring.profiles.active")) {
                activeApplicationConfig = base.asStr("spring.profiles.active");

            } else if (base.contains("spring", "profiles.active")) {
                activeApplicationConfig = base.asStr("spring", "profiles.active");

            } else if (base.contains("spring", "profiles", "active")) {
                activeApplicationConfig = base.asStr("spring", "profiles", "active");
            }
        }

        if (StringUtils.isNotBlank(activeApplicationConfig)) {
            localConfigs.add(CONFIG_DIR_PATH + APPLICATION_FILE_PREFIX + activeApplicationConfig + APPLICATION_FILE_SUFFIX);
        }

        JsonNode baseAllConfig = YvanUtil.readYamlNode(localConfigs);
        return baseAllConfig;
    }

    public JsonNode getExtConfig(JsonNode baseConfig) {
        JsonNode extNodeConfig = null;
        JsonWapper jwBaseConfig = YvanUtil.node2Wapper(baseConfig);
        if (jwBaseConfig.contains("config")) {
            SettingProperties baseLocal = jwBaseConfig.asObject(SettingProperties.class, "config");
            System.out.println(baseLocal.getUrl());
            extNodeConfig = YvanUtil.readYamlInner(baseLocal);
        }
        return extNodeConfig;
    }

    private Map<String, String> readApplicationConfig() {

        JsonNode baseConfig = getBaseApplicationConfig();
        JsonNode extConfig = getExtConfig(baseConfig);
        JsonNode allConfig = baseConfig;
        if (extConfig != null) {
            allConfig = YvanUtil.merge(baseConfig, extConfig);
        }

        Map<String, String> envMap = new LinkedHashMap<>();
        translate(allConfig, "", envMap);
        return envMap;
    }


    private void translate(JsonNode config, String parent, Map<String, String> envMap) {

        Iterator<String> fieldNames = config.fieldNames();
        while (fieldNames.hasNext()) {
            String fieldName = fieldNames.next();
            String parentNames;
            if (parent.length() > 0) {
                parentNames = parent + "." + fieldName;
            } else {
                parentNames = fieldName;
            }

            JsonNode child = config.get(fieldName);
            if (!child.isObject() && !child.isArray()) {
                if (child.isNull()) {
                    System.out.println(parentNames + " value is null,ignore it");
                } else {
                    envMap.put(parentNames, child.asText());
                }
            } else {
                if (child != null && child.isObject()) {
                    translate(child, parentNames, envMap);
                } else {
                    if (child != null && child.isArray()) {
                        for (JsonNode node : child) {
                            translate(node, parentNames, envMap);
                        }
                    } else if (child instanceof ObjectNode) {
                        translate(child, parentNames, envMap);
                    } else {
                        System.out.println("config client translate with unknown child type,ignore it");
                    }
                }
            }
        }
    }
}
